import { ref, Ref, reactive, onMounted } from 'vue';
import _ from 'lodash';
import OpenSeadragon from 'openseadragon';
import { fabric } from "fabric";
import { Message } from '@arco-design/web-vue';
import { useMarkLesionStore } from '@/store';
import { saveAnnoData } from '@/api/readPathology/readPathology';
import type { Canvas, IEvent, StaticCanvas } from 'fabric/fabric-impl';
import type * as Temp from './type.d';
import type * as Type from '@/api/readPathology/readPathology.d';
import { changePoint } from './util';


export default function useFabricTool(
        fabricCanvas: Ref<Canvas | null>, 
        viewer: Ref<OpenSeadragon.Viewer>, 
        pencilColor: Ref<string>, 
        pencilWidth: Ref<number>, 
        currentItem: Ref<number>,
        showLesionList: Ref<Temp.NidusList[]>,
        slideInfo: Ref<Temp.SlideInfo>,
        alrId: Ref<number>,
        arListData: Ref<Type.ArItem[] | null>,
        getInitData: Function
    ) {
    // 标注绘画状态
    let doDrawing = ref<boolean>(false);
    // 起始点坐标
    let mouseFrom = reactive({
        x: 0,
        y: 0
    });
    // 结束点坐标
    let mouseTo = reactive({
        x: 0,
        y: 0
    });
    // 移动点位计数
    let moveCount = ref<number>(0);
    // 正在绘制的对象
    let currCanvasObject = ref();
    // 绘制的标注对象
    let canvasObject = ref();
    // 绘制的标注文本对象
    let textObject = ref();
    // 当前图片的实际缩放倍率
    let actualZoom = ref<number>(0);
    // 绘制的当前组对象
    let groupObject = ref();
    // 临时记录当前工具选中对象
    const currentMarkItem = ref<Temp.NidusItem>();
    // 基础标注工具配置项参数
    let commonParams = reactive({
        // 标注工具的描边初始颜色
        stroke: pencilColor.value,
        // 标注工具的描边初始宽度
        strokeWidth: pencilWidth.value,
        // 标注工具的填充初始颜色，设置为透明不然会画出一个实心标注
        fill: "rgba(255, 255, 255, 0)",
        // 是否显示调整的控制器 true为显示 false隐藏
        hasControls: true,
        // 是否显示控制器边框 true显示 false隐藏
        hasBorders: false,
        // 控制器是否为填充 true为透明 false为填充
        transparentCorners: false,
        // 是否可以旋转 false为不可以旋转 true为可旋转
        hasRotatingPoint: false,
        // 是否允许选中 true不允许选中 false允许选中
        skipTargetFind: true,
        // 元素区域而不是边框 true为空白区不可选 false为空白区域可选中
        perPixelTargetFind: true,
        // 控件是否可以选择 false为不可以被选择 true为可以被选择
        selectable: false,
        // 记录绘制时倍率
        acZoom: 0,
        // 当前标注对象类型
        type: '',
        // 选框填充色
        selectionColor: 'transparent',
        // 选框边框颜色
        selectionBorderColor: 'transparent',
        // 禁止旋转 true为禁止 false为放开 默认false
        lockRotation: true,
        // 是否以中心店缩放 默认是true以中心点缩放 false不是中心点
        centeredScaling: false,
        // 是否限制边框缩放 默认false不限制 true限制
        strokeUniform: true,
        selection: false,
        // borderColor: '#1FFF79', // 边框颜色
        // cornerColor: '#1FFF79', // 控制角颜色
        // cornerSize: 10, // 控制角大小
    });
    let downDate = 0;
    let upDate = 0;
    // 鼠标点下
    const mouseDown = (options: IEvent<MouseEvent>) => {
        downDate = Date.now();
        // 记录画布鼠标按下时的x偏移量
        const offsetX = window.frabicCanvas.calcOffset().viewportTransform[4];
        // 记录画布鼠标按下时的y偏移量
        const offsetY = window.frabicCanvas.calcOffset().viewportTransform[5];
        // 根据x偏移量计算实际x坐标
        // const x: number = Math.round(options.e.offsetX - offsetX);
        const x = options.e.offsetX - offsetX;
        // 根据y偏移量计算实际y坐标
        // const y: number = Math.round(options.e.offsetY - offsetY);
        const y = options.e.offsetY - offsetY;
        // 存储x坐标
        mouseFrom.x = x;
        // 存储y坐标
        mouseFrom.y = y;
        // 当前点击的坐标并创建成openseadragon的点位
        const pos = new OpenSeadragon.Point(options.e.x, options.e.y);
        // 根据当前openseadragon的点位将window的点位转换成图片上的点位
        const imagePos = viewer.value.viewport.windowToImageCoordinates(pos);
        // 根据window所在图片上的点位查看当前点位是否超过图像区域，否则禁止绘制
        if (imagePos.x < 0 || imagePos.x > Number(slideInfo.value.Width) || imagePos.y < 0 || imagePos.y > Number(slideInfo.value.Height)) {
            doDrawing.value = false;
        } else {
            doDrawing.value = true;
        };
    };

    // 获取存储对象
    const markLesionStore = useMarkLesionStore();
    
    // 鼠标移动
    const mouseMove = (options: any) => {
        // 关闭viewer图片容器的所有鼠标事件，允许画布绘制
        viewer.value.setMouseNavEnabled(false);
        // 判断当前绘制锁状态 为true允许绘制
        if (doDrawing.value) {
            // 减少绘制频率
            if (moveCount.value % 2 && !doDrawing.value) return;
            // 记录鼠标移动数量
            moveCount.value++;
            // 记录画布鼠标移动时的x偏移量
            const offsetX = window.frabicCanvas.calcOffset().viewportTransform[4];
            // 记录画布鼠标移动时的y偏移量
            const offsetY = window.frabicCanvas.calcOffset().viewportTransform[5];
            // 根据x偏移量计算实际x坐标
            // const x = Math.round(options.e.offsetX - offsetX);
            const x = options.e.offsetX - offsetX;
            // const x = options.e.clientX;
            // 根据y偏移量计算实际y坐标
            // const y = Math.round(options.e.offsetY - offsetY);
            const y = options.e.offsetY - offsetY;
            // const y = options.e.clientY;
            options.e.target?.className === "upper-canvas " && (mouseTo.x = x);
            options.e.target?.className === "upper-canvas " && (mouseTo.y = y);
            // 移除上一次残留，一面重复绘制导致绘制异常
            if(currCanvasObject.value) window.frabicCanvas?.remove(currCanvasObject.value);
            // 获取图片容器倍率
            const zoom = viewer.value.viewport.getZoom(true);
            // 获取容器在图片上的倍率
            const canZoom = viewer.value.viewport.viewportToImageZoom(zoom);
            // 获取标注画布倍率
            const canvasZoom = window.frabicCanvas?.getZoom();
            // 根据标注画布上点位转换成图像上x,y点位
            const mouseFromPoint = new OpenSeadragon.Point(mouseFrom.x, mouseFrom.y);
            const mouseFormView = viewer.value.viewport.windowToImageCoordinates(mouseFromPoint);
            const mouseToPoint = new OpenSeadragon.Point(mouseTo.x, mouseTo.y);
            const mouseToView = viewer.value.viewport.windowToImageCoordinates(mouseToPoint);
            // 获取标注的宽 高 横向弧度 纵向弧度
            // const width = Math.round(Math.abs(mouseToView.x - mouseFormView.x) * Number(slideInfo.value.Mpp) * 100) / 100;
            // const height = Math.round(Math.abs(mouseToView.y - mouseFormView.y) * Number(slideInfo.value.Mpp) * 100) / 100;
            const width = Math.round(Math.abs(mouseToView.x - mouseFormView.x) * 100) / 100;
            const height = Math.round(Math.abs(mouseToView.y - mouseFormView.y) * 100) / 100;
            const rxRadius = width / 2;
            const ryRadius = height / 2;
            // 获取实际倍率
            actualZoom.value = getActualNum();
            commonParams.acZoom = viewer.value.viewport.getZoom() / actualZoom.value;
            // 通过当前病灶变更初始笔刷颜色
            if (markLesionStore.currentLesion.color !== '' && [6, 7].includes(currentItem.value)) {
                commonParams.stroke = markLesionStore.currentLesion.color;
            } else {
                commonParams.stroke = pencilColor.value;
            }
            // 画尺子
            // 长度
            const lineLength = Math.round(Math.sqrt(width * width + height * height) * 100) / 100;
            currentItem.value === 4 && (groupObject.value = drawLine(canvasObject.value, mouseFrom, mouseTo, commonParams, canZoom, textObject.value, lineLength, groupObject.value));
            // 画矩形
            currentItem.value === 6 && (canvasObject.value = drawRect(canvasObject.value, mouseFrom, mouseTo, commonParams, canZoom));
            // 计算椭圆的距顶距左距离以及短轴，长轴值
            let rx = Math.abs(mouseFrom.x - mouseTo.x) / 2;
            let ry = Math.abs(mouseFrom.y - mouseTo.y) / 2;
            let top = mouseTo.y > mouseFrom.y ? mouseFrom.y : mouseFrom.y - ry * 2;
            let left = mouseTo.x > mouseFrom.x ? mouseFrom.x :  mouseFrom.x - rx * 2;
            // let rx = Math.abs(mouseFrom.x - mouseTo.x) / canZoom / 2;
            // let ry = Math.abs(mouseFrom.y - mouseTo.y) / canZoom / 2;
            // let top = mouseTo.y > mouseFrom.y ? mouseFrom.y / canZoom : mouseFrom.y / canZoom - ry * 2;
            // let left = mouseTo.x > mouseFrom.x ? mouseFrom.x / canZoom :  mouseFrom.x / canZoom - rx * 2;
            // 画椭圆
            currentItem.value === 7 && (canvasObject.value = drawEllipse(canvasObject.value, top, left, rx, ry, commonParams, canZoom));
            // 判断裱糊对象是否存在，并记录当前对象及渲染
            if (currentItem.value !== 4) {
                currCanvasObject.value = canvasObject.value;
                window.frabicCanvas?.add(currCanvasObject.value);
            } else {
                window.frabicCanvas.selectable = false;
                window.frabicCanvas.selection = false;
                currCanvasObject.value = groupObject.value;
                window.frabicCanvas?.add(currCanvasObject.value);
            }
        };
    };

    // 绘制直线
    const drawLine = (canvasObject: fabric.Line, mouseFrom: { x: number; y: number; }, mouseTo: { x: number; y: number; }, commonParams: fabric.ILineOptions | undefined, canZoom: number, textObject: fabric.Text, lineLength: number, groupObject: fabric.Group) => {
        commonParams!.type = 'line';
        canvasObject = new fabric.Line([mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y], {
            ...commonParams,
        });
        // 文本
        // 计算文本倾斜角度
        // const angle = Math.atan2(mouseFrom.y - mouseTo.y, mouseFrom.x - mouseTo.x) * 180 / Math.PI;
        let angle = Math.atan(Math.abs(mouseFrom.y - mouseTo.y) / Math.abs(mouseFrom.x - mouseTo.x)) / (Math.PI / 180) - 90;
        // console.log(angle, 'angle');
        // if ((mouseFrom.x > mouseTo.x && mouseFrom.y > mouseTo.y) || (mouseFrom.x < mouseTo.x && mouseFrom.y > mouseTo.y)) {
        //     // 左下往右上 或者 右上往左下
        //     angle = 360 - Math.abs(angle);
        // } else {
        //     // 右下往左上 或者 左上往右下
        //     angle = Math.abs(angle);
        // }
        textObject = new fabric.Text(`${lineLength}mm`, {
            top: Math.min(mouseFrom.y, mouseTo.y),
            left: Math.min(mouseFrom.x, mouseTo.x) + (Math.min(mouseFrom.x, mouseTo.x) / 5),
            fontSize: 20,
            originX: "center",
            originY: "center",
            // angle: Math.abs(angle)
        })
        groupObject = new fabric.Group([canvasObject, textObject], { 
            type: 'group',
            borderColor: 'transparent', // 边框颜色
            cornerColor: 'transparent', // 控制角颜色
            cornerSize: 10, // 控制角大小
            // 控制器是否为填充 true为透明 false为填充
            transparentCorners: false,
            hasControls: false,
            lockScalingX: true,
            lockScalingY: true,
            lockRotation: true,
            lockMovementX: true,
            lockMovementY: true,
            perPixelTargetFind: true
        });
        return groupObject; 
    };

    // 绘制矩形
    const drawRect = (canvasObject: fabric.Rect, mouseFrom: { x: number; y: number; }, mouseTo: { x: number; y: number; }, commonParams: fabric.ILineOptions | undefined, canZoom: number) => {
        commonParams!.type = 'rect';
        commonParams!.borderColor = '#1FFF79';
        commonParams!.cornerColor = '#1FFF79';
        commonParams!.cornerSize = 10;
        canvasObject = new fabric.Rect({
            top: Math.min(mouseFrom.y, mouseTo.y),
            left: Math.min(mouseFrom.x, mouseTo.x),
            width: Math.abs(mouseFrom.x - mouseTo.x),
            height: Math.abs(mouseFrom.y - mouseTo.y),
            ...commonParams
        });
        return canvasObject;
    };

    // 绘制椭圆
    const drawEllipse = (canvasObject: fabric.Ellipse, top: number, left: number, rx: number, ry: number, commonParams: fabric.ILineOptions | undefined, canZoom: number) => {
        commonParams!.type = 'ellipse';
        commonParams!.borderColor = '#1FFF79';
        commonParams!.cornerColor = '#1FFF79';
        commonParams!.cornerSize = 10;
        canvasObject = new fabric.Ellipse({
            top,
            left,
            rx,
            ry,
            ...commonParams
        });
        return canvasObject;
    }

    // 鼠标抬起
    const mouseUp = (options: IEvent<MouseEvent>, item?: Temp.NidusItem) => {
        upDate = Date.now();
        if (upDate - downDate < 1000) {
            window.frabicCanvas?.off('mouse:move');
            window.frabicCanvas?.off('mouse:up');
        }
        const offsetX = window.frabicCanvas.calcOffset().viewportTransform[4];
        const offsetY = window.frabicCanvas.calcOffset().viewportTransform[5];
        // mouseTo.x = Math.round(options.e.offsetX - offsetX);
        mouseTo.x = options.e.offsetX - offsetX;
        // mouseTo.y = Math.round(options.e.offsetY - offsetY);
        mouseTo.y = options.e.offsetY - offsetY;
        // 过滤掉鼠标之间按下抬起没画任何图形
        if (mouseFrom.x === mouseTo.x && mouseFrom.y === mouseTo.y) {
            // 最后绘制的标注存在并重置属性，以免出现绘制不上去问题
            resetCanvasOption();
            return;
        };
        // 鼠标抬起并保存当前标注
        if (currCanvasObject.value && currentItem.value !== 4) {
            saveMark();
        }
        if (currCanvasObject.value && currentItem.value === 4) {
            saveLocal();
        }
        // 最后绘制的标注存在并重置属性，以免出现绘制不上去问题
        currCanvasObject.value && resetCanvasOption();
    };

    // 绘画结束后重置属性避免污染画布
    const resetCanvasOption = () => {
        doDrawing.value = false;
        currCanvasObject.value = null;
        canvasObject.value = null;
        textObject.value = null;
        groupObject.value = null;
        moveCount.value = 1;
        mouseFrom = {
            x: 0,
            y: 0
        };
        mouseTo = {
            x: 0,
            y: 0
        };
        // viewer.value.setMouseNavEnabled(true);
        // window.frabicCanvas?.off('mouse:down');
        window.frabicCanvas?.off('mouse:move');
        window.frabicCanvas?.off('mouse:up');
    };

    // 标注结果
    const markResultObj = ref({
        lesion: '',
        tool: '',
        color: '',
        result: ''
    });

    // 保存当前标注根据传递id追加到病灶列表数据中
    const saveMark = async () => {
        if (markLesionStore.currentLesion.color) {
            // 处理数据保存为左侧病灶列表
            const { lesion, color, ...newMarkCur } = markLesionStore.currentLesion;
            const tempObj = {
                data: {
                    point1: { ...changePoint(viewer, mouseFrom, true) },
                    point2: { ...changePoint(viewer, mouseTo, true) },
                    // point1: { ...mouseFrom },
                    // point2: { ...mouseTo },
                },
                acZoom: commonParams.acZoom,
                version: '4.6.0'
            }
            let newType = '';
            if (commonParams?.type === 'rect') newType = 'RECTANGLE';
            if (commonParams?.type === 'ellipse') newType = 'ELLIPSE';
            markResultObj.value = {
                lesion,
                color,
                tool: newType,
                result: JSON.stringify(tempObj)
            }
            // 保存数据
            const params: Type.AddAnnoParams = {
                arId: arListData.value! && arListData.value[0].id,
                ...markResultObj.value
            }
            // 由于异步请求接口，所以临时存储标注对象
            const res = await saveAnnoData(params);
            alrId.value = res.data?.alrId;
            Message.success('新增标注成功！');
            // 根据病灶列表的数据清除当前画布标注
            window.frabicCanvas?.clear();
            getInitData(true);
        };
    };

    // 保存当前尺子标注并随机创建一个id插入集合中
    const saveLocal = () => {
        currCanvasObject.value.id = new Date().valueOf();
        currCanvasObject.value.acZoom = commonParams.acZoom;
        const mouseFromPoint = new OpenSeadragon.Point(mouseFrom.x, mouseFrom.y);
        const mouseFormView = viewer.value.viewport.windowToImageCoordinates(mouseFromPoint);
        const mouseToPoint = new OpenSeadragon.Point(mouseTo.x, mouseTo.y);
        const mouseToView = viewer.value.viewport.windowToImageCoordinates(mouseToPoint);
        const width = Math.round(Math.abs(mouseToView.x - mouseFormView.x) * Number(slideInfo.value.Mpp) * 100) / 100;
        const height = Math.round(Math.abs(mouseToView.y - mouseFormView.y) * Number(slideInfo.value.Mpp) * 100) / 100;
        currCanvasObject.value.acWidth = width;
        currCanvasObject.value.acHeight = height;
        window.frabicCanvas?.renderAll();
        const fabricJsonObj = window.frabicCanvas?.toObject(['id', 'acZoom', 'acWidth', 'acHeight'])!;
        fabricJsonObj.objects = fabricJsonObj.objects.filter((item: { type: string; }) => item.type === 'group');
        let angle = Math.atan(Math.abs(mouseFrom.y - mouseTo.y) / Math.abs(mouseFrom.x - mouseTo.x)) / (Math.PI / 180) - 90;
        fabricJsonObj.objects = fabricJsonObj.objects.map((item: any) => {
            if (item.id === currCanvasObject.value.id) {
                item = {
                    id: currCanvasObject.value.id,
                    data: {
                        point1: { ...mouseFrom },
                        point2: { ...mouseTo },
                    },
                    acZoom: commonParams.acZoom,
                    acWidth: width,
                    acHeight: height,
                    angle
                }
            }
            return item;
        })
        localStorage.setItem('markData', JSON.stringify(fabricJsonObj));
        // 根据病灶列表的数据清除当前画布标注
        window.frabicCanvas?.clear();
        getInitData(true);
    };

    // 获取实际比例
    const getActualNum = () => {
        const originImgWidth = Number(slideInfo.value?.Width);
        const Magnification = Number(slideInfo.value?.Magnification) || 20;
        const containerWidth = Number(viewer.value.container?.clientWidth);
        return originImgWidth / Magnification / containerWidth;
    };

    return {
        doDrawing,
        alrId,
        mouseDown,
        mouseMove,
        mouseUp,
        getActualNum,
        markResultObj
    };
};